package com.taomus.mytools.asmuitls;

import java.io.PrintStream;
import java.io.PrintWriter;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.objectweb.asm.commons.Method;
import org.objectweb.asm.util.TraceClassVisitor;

public class SimpleAsmUtils  extends ClassLoader {
	private ClassWriter cw1 = null;
	private TraceClassVisitor cw=null;
	private GeneratorAdapter ga = null;
	private String name;
	public SimpleAsmUtils() {
		cw1 = new ClassWriter(ClassWriter.COMPUTE_MAXS);
		cw = new TraceClassVisitor(cw1, new PrintWriter(System.out));
	}
	
	public SimpleAsmUtils(String name) {
		this();
		this.createConstructor(name);
	}
	
	public void createFied(String name,Class<?> tlass){
		int defaultScope = Opcodes.ACC_PUBLIC;
		cw.visitField(defaultScope, name,Type.getType(tlass).getDescriptor(),null,null).visitEnd();
	}
	public void setField(String name,Class<?> type,ICode icode){
		ga.loadThis();
		if(null != icode){
			icode.code(ga);
		}
		ga.putField(Type.getType(this.name), name,Type.getType(type));
	}
	public void setField(String name,String type,ICode icode){
		ga.loadThis();
		if(null != icode){
			icode.code(ga);
		}
		ga.putField(Type.getType(this.name), name,Type.getType(type));
	}
	
	public void getField(String name,String type){
		ga.loadThis();
		ga.getField(Type.getType(this.name), name, Type.getType(type));
	}
	
	public void getField(String name,Class<?> cl){
		ga.loadThis();
		ga.getField(Type.getType(this.name), name,Type.getType(cl));
	}
	
	public void createConstructor(String name) {
		this.name = name;
		cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC, name, null, "java/lang/Object", null);
		Method m = Method.getMethod("void <init>()");
		GeneratorAdapter ga = new GeneratorAdapter(Opcodes.ACC_PUBLIC, m, null, null, cw);
		ga.loadThis();
		ga.invokeConstructor(Type.getType(Object.class), m);
		ga.returnValue();
		ga.endMethod();
	}
	public void createMethod(String m) {
		Method method = Method.getMethod(m);
		int defaultScope = Opcodes.ACC_PUBLIC;
		ga = new GeneratorAdapter(defaultScope, method, null, null, cw);
	}
	public void addStatic(Type owner,String name,Type type){
		ga.getStatic(owner, name, type);
	}
	public void addInvoke(Type owner,String m){
		ga.invokeVirtual(owner,Method.getMethod(m));
	}
	public void addInvokeInterface(Type owner,String m){
		ga.invokeInterface(owner,Method.getMethod(m));
	}
	/**
	 * @param methodName
	 * @param type
	 * @param bsm
	 * @param bsmArgs
	 */
	public void addInvokeDynamic(String methodName,String type,Handle bsm,Object...bsmArgs){
		ga.invokeDynamic(methodName, type, bsm, bsmArgs);
	}
	
	public void end(){
		ga.returnValue();
		ga.endMethod();
	}
	
	public void cend(){
		cw.visitEnd();
	}
	
	
	public static String addValue(GeneratorAdapter ga,Object value){
		if(value instanceof Boolean){
			ga.push((Boolean)value);
			return "Boolean";
		}else if(value.equals(boolean.class)){
			ga.push((Boolean)value);
			return "boolean";
		}else if(value.equals(int.class)){
			ga.push((Integer)value);
			return "int";
		}else if(value instanceof Integer){
			ga.push((Integer)value);
			return "Integer";
		}else if(value.equals(double.class)){
			ga.push((Double)value);
			return "double";
		}else if(value instanceof Double){
			ga.push((Double)value);
			return "Double";
		}else if(value.equals(float.class)){
			ga.push((Float)value);
			return "float";
		}else if(value instanceof Float){
			ga.push((Float)value);
			return "Float";
		}else if(value.equals(long.class)){
			ga.push((Long)value);
			return "long";
		}else if(value instanceof Long){
			ga.push((Long)value);
			return "Long";
		}else if(value instanceof String){
			ga.push((String)value);
			return "String";
		}else if(value instanceof Handle){
			ga.push((Handle)value);
		}else if(value instanceof Type){
			ga.push((Type)value);
		}
		return "String";
	}
	
	public void addCode(ICode icode){
		if(null != icode){
			icode.code(ga);
		}
	}
	
	public void IF(int opcodes,IIF icode){
		if(null != icode){
			Label label = ga.newLabel();
			icode._if(ga);
			ga.visitJumpInsn(opcodes, label);
			icode.code(ga);
			ga.visitLabel(label);
		}
	}
	
	public void GOTO(int opcodes,IIF icode){
		if(null != icode){
			Label label = ga.newLabel();
			ga.goTo(label);
			Label iflable = ga.newLabel();
			ga.visitLabel(iflable);
			icode.code(ga);
			ga.visitLabel(label);
			icode._if(ga);
			ga.visitJumpInsn(opcodes, iflable);
		}
	}
	
	public Class<?> loadClass2(String name){
		byte[] bytes = cw1.toByteArray();
		System.out.println(bytes.length);
		Class<?> cl = this.defineClass(name,bytes,0,bytes.length);
		return cl;
	}
}
